/*******************************************************************************
* Copyright (c) 2008 Olivier Moises
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Olivier Moises- initial API and implementation
*******************************************************************************/
package org.eclipse.wazaabi.engine.core.editparts.stylerules;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Properties;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.wazaabi.mm.core.styles.CoreStylesPackage;
import org.eclipse.wazaabi.mm.core.styles.StyleRule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class StyleRulesHelper {
public static final String STYLE_PROPERTY_DEFINITION_URI = "http://www.wazaabi.org/style/property/definition"; //$NON-NLS-1$
public static final String PACKAGE_KEYWORD = "package"; //$NON-NLS-1$
public static final String ECLASS_KEYWORD = "EClass"; //$NON-NLS-1$
private static final String PACKAGE_PREFIX = PACKAGE_KEYWORD + "="; //$NON-NLS-1$
private static final String ECLASS_PREFIX = ECLASS_KEYWORD + "="; //$NON-NLS-1$
final static Logger logger = LoggerFactory
.getLogger(StyleRulesHelper.class);
public static void buildCoreStylePropertyDescriptors(EClass eClass,
HashMap<String, StylePropertyDescriptor> descriptors) {
for (EClass ancestor : eClass.getEAllSuperTypes())
if (!CoreStylesPackage.Literals.STYLED_ELEMENT.equals(ancestor)
&& CoreStylesPackage.Literals.STYLED_ELEMENT
.isSuperTypeOf(ancestor))
addStyleDefinitions(ancestor, descriptors);
addStyleDefinitions(eClass, descriptors);
}
public static void buildPlatformSpecificStylePropertyDescritors(
EClass eClass, HashMap<String, StylePropertyDescriptor> descriptors) {
for (EClass ancestor : eClass.getEAllSuperTypes())
addStyleDefinitions(ancestor, descriptors);
addStyleDefinitions(eClass, descriptors);
}
protected static void addStyleDefinitions(EClass eClass,
HashMap<String, StylePropertyDescriptor> descriptors) {
for (EAnnotation annotation : eClass.getEAnnotations()) {
StylePropertyDescriptor descriptor = createStylePropertyDescriptor(annotation);
if (descriptor != null)
descriptors.put(descriptor.getName(), descriptor);
}
}
/**
* Creates a StylePropertyDescriptor by parsing the given annotation. This
* EAnnotation is parsed only if its source is
* 'http://www.wazaabi.org/style/property/definition' and if all the
* mandatory details are well formed and drive to non null values.
*
* @param annotation
* Any EAnnotation
*
* @return A StylePropertyDescriptor if found, null otherwise.
*/
protected static StylePropertyDescriptor createStylePropertyDescriptor(
EAnnotation annotation) {
if (STYLE_PROPERTY_DEFINITION_URI.equals(annotation.getSource())) {
String name = annotation.getDetails().get("name"); //$NON-NLS-1$
if (name == null || "".equals(name)) //$NON-NLS-1$
throw new RuntimeException("No name found in an annotation of " //$NON-NLS-1$
+ ((EClass) annotation.getEModelElement()).getName());
EClass type = resolveEClass(annotation);
if (type == null)
throw new RuntimeException(
"No type resolved in annotation whose name is " //$NON-NLS-1$
+ annotation.getDetails().get("name") //$NON-NLS-1$
+ " in " //$NON-NLS-1$
+ ((EClass) annotation.getEModelElement())
.getName());
return new StylePropertyDescriptor(name, type, buildDefault(
annotation, type));
}
return null;
}
/**
* Returns an EClass using the description found in the 'type' of a
* EAnnotation. This method checks also that expected values are well
* provided.
*
* @param annotation
* An StyleDescriptor EAnnotation whose name is not null or blank
*
* @return An EClass if found, null otherwise
*/
protected static EClass resolveEClass(EAnnotation annotation) {
EClass result = null;
String packageURI = null;
String className = null;
final String typeDescription = annotation.getDetails().get("type"); //$NON-NLS-1$
if (typeDescription == null || "".equals(typeDescription)) //$NON-NLS-1$
throw new RuntimeException(
"No type described in annotation whose name is " //$NON-NLS-1$
+ annotation.getDetails().get("name") //$NON-NLS-1$
+ " in " //$NON-NLS-1$
+ ((EClass) annotation.getEModelElement())
.getName());
String lines[] = typeDescription.split("[\\r\\n]+"); //$NON-NLS-1$
for (String line : lines)
if (line.startsWith(PACKAGE_PREFIX))
packageURI = line.substring(PACKAGE_PREFIX.length());
else if (line.startsWith(ECLASS_PREFIX))
className = line.substring(ECLASS_PREFIX.length());
else
throw new RuntimeException(
"Only " //$NON-NLS-1$
+ PACKAGE_KEYWORD //$NON-NLS-1$
+ " and " //$NON-NLS-1$
+ ECLASS_KEYWORD //$NON-NLS-1$
+ " are allowed in a 'type' details of EAnnotation whose name is " //$NON-NLS-1$
+ annotation.getDetails().get("name") //$NON-NLS-1$
+ " in " //$NON-NLS-1$
+ ((EClass) annotation.getEModelElement())
.getName());
if (packageURI != null && !"".equals(packageURI)) {
EPackage ePackage = EPackage.Registry.INSTANCE
.getEPackage(packageURI);
if (ePackage != null
&& ePackage.getEClassifier(className) instanceof EClass)
result = (EClass) ePackage.getEClassifier(className);
else
throw new RuntimeException(
"No EPackage found in annotation whose name is " //$NON-NLS-1$
+ annotation.getDetails().get("name") //$NON-NLS-1$
+ " in " //$NON-NLS-1$
+ ((EClass) annotation.getEModelElement())
.getName());
} else
throw new RuntimeException(
"Bad EPackage declaration in annotation whose name is " //$NON-NLS-1$
+ annotation.getDetails().get("name") //$NON-NLS-1$
+ " in " //$NON-NLS-1$
+ ((EClass) annotation.getEModelElement())
.getName());
return result;
}
/**
* Builds a default EObject by iterating over the annotation 'default'
* content. When found, attributes are set using conversion mechanisms. All
* the attribute are not supposed to be set.
*
* @param annotation
* A non null EAnnotation whose 'name' is not null.
* @param eClass
* The EClass of the EObject to create
* @return An EObject if the build mechanisms succeded.
*/
protected static StyleRule buildDefault(EAnnotation annotation,
EClass eClass) {
EObject result = null;
final String content = annotation.getDetails().get("default"); //$NON-NLS-1$
if (content == null || "".equals(content)) //$NON-NLS-1$
return null;
try {
Properties defaultValues = new Properties();
defaultValues.load(new ByteArrayInputStream(content
.getBytes("UTF-8")));
result = EcoreUtil.create(eClass);
@SuppressWarnings("rawtypes")
Iterator iterator = defaultValues.entrySet().iterator();
while (iterator.hasNext()) {
@SuppressWarnings("unchecked")
Entry<String, String> entry = (Entry<String, String>) iterator
.next();
EAttribute attr = getEAttribute(eClass, entry.getKey());
if (attr != null) {
EDataType attrType = attr.getEAttributeType();
if (attrType instanceof EEnum) {
EEnumLiteral eEnumLiteral = ((EEnum) attrType)
.getEEnumLiteral(entry.getValue());
if (eEnumLiteral != null)
result.eSet(attr, eEnumLiteral.getInstance());
} else
switch (attrType.getClassifierID()) {
case EcorePackage.EBOOLEAN:
result.eSet(attr,
Boolean.parseBoolean(entry.getValue()));
break;
// TODO : continue to implement conversion mechanisms
default:
throw new RuntimeException(
"No conversion mechanism for " + //$NON-NLS-1$
(((EClass) annotation
.getEModelElement())
.getName())
+ "." //$NON-NLS-1$
+ annotation.getDetails().get(
"name") + //$NON-NLS-1$
".default"); //$NON-NLS-1$
}
} else
throw new RuntimeException(
"Unable to find an attribute for " + //$NON-NLS-1$
(((EClass) annotation.getEModelElement())
.getName()) + "." //$NON-NLS-1$
+ annotation.getDetails().get("name")); //$NON-NLS-1$
}
} catch (IOException e) {
throw new RuntimeException("Unable to read default for " + //$NON-NLS-1$
(((EClass) annotation.getEModelElement()).getName()) + "." //$NON-NLS-1$
+ annotation.getDetails().get("name")); //$NON-NLS-1$
}
return (StyleRule) result;
}
/**
* Simply returns an EAttribute of the given EClass knowing its name
*
* @param eClass
* The EClass where the EAttribute is supposed to be located in.
* @param name
* The attribute's name
* @return Null if no attribute with this name exists in this class
*/
private static EAttribute getEAttribute(EClass eClass, String name) {
for (EAttribute attr : eClass.getEAllAttributes())
if (attr.getName().equals(name))
return attr;
return null;
}
}